package mrusanov.player

import mrusanov.view._
import io.Source
import java.io.File
import xml.{NodeSeq, Node, XML}
import mrusanov.terrain.TerrainType
import mrusanov.images.ImageInfo


object PlayerTypeInfoLoader {
  lazy val types:Map[String, PlayerTypeInfo] = loadPlayerSprites

  private def loadPlayerSprites:Map[String, PlayerTypeInfo] = {
    val path = getClass.getResource("/conf/playerTypes.xml").toURI
    val xml = XML.loadFile(new File(path))

    val retMap = (xml\"playerType").map(pt => {
      val playerTypeName = (pt \ "@name") toString()
      val view = parsePlayerTypeView(pt)
      val favoriteTerrainString = (pt \ "@favorite").toString()
      val favorite = TerrainType.parseTypes(favoriteTerrainString)
      val hatedTerrainString = (pt \ "@hated").toString()
      val hated = TerrainType.parseTypes(hatedTerrainString)
      val agility = (pt \ "@agility").toString().toInt
      val hpToDamage = (pt \ "@hpToDamage").toString().toFloat
      val damageTypeString = (pt \ "@damageType").toString()
      val damageType = DamageType.damageTypeByName(damageTypeString)
      val resistances = parseResistances((pt \ "@resistances").toString())

      (playerTypeName -> new PlayerTypeInfo(playerTypeName, view, favorite, hated, hpToDamage, agility,
        damageType, resistances))
    })

    retMap.toMap
  }

  private def parseResistances(res:String):Map[DamageType, Int] = {
    val pairs = res.split(",")
    val splitPairs = pairs map (_.split(":"))
    splitPairs.map(ar => (DamageType.damageTypeByName(ar(0)) -> ar(1).toInt)).toMap
  }

  private def parsePlayerTypeView(node:Node):PlayerTypeView = {
     val sprites =  Vector() ++ (node \ "sprite").map(parsePlayerSprite)

    validatePlayerSpritesFromLevelField(sprites)
    val levels = (sprites map (_._2)).flatten
    val spritesOnly = sprites map (_._1)
    new PlayerTypeView(spritesOnly, levels)
  }

  private def validatePlayerSpritesFromLevelField(list:IndexedSeq[(PlayerSpriteInfo, Option[Int])]) {
     list.zipWithIndex.foreach(infoIndex => {
       infoIndex._2 match {
         case 0 => require(infoIndex._1._2.isEmpty, "First sprite info is not allowed to have fromLevel attribute set!")
         case _ => require(infoIndex._1._2.isDefined, "Second and next sprite info must have fromLevel attribute set!")
       }
     })
  }

  private def parsePlayerSprite(spr:Node):(PlayerSpriteInfo, Option[Int]) = {
      val name = (spr \ "@name").toString()
      val fromLevelAttr = spr \ "@fromLevel"
      val fromLevel = if (fromLevelAttr.isEmpty) None
                      else Some(fromLevelAttr.toString().toInt)


    val info = PlayerSpriteInfoLoader.info(name)
    (info, fromLevel)
  }


}
